package kevin.framework.basic.common.utils;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.RequestContextUtils;

import com.alibaba.fastjson.JSONObject;

import kevin.framework.basic.common.thread.LangThreadHodler;
import kevin.framework.basic.common.thread.OperatorDataHolder;
import kevin.framework.basic.common.thread.RequestThreadHolder;
import kevin.framework.basic.common.thread.ResponseThreadHolder;
import kevin.framework.basic.common.thread.ThreadHolderClearer;
import kevin.framework.basic.common.ui.AdminControllerHelper;
import kevin.framework.basic.common.ui.AjaxResult;
import kevin.framework.basic.common.ui.LanguageMap;
import kevin.framework.basic.common.ui.LanguageStore;
import kevin.framework.basic.common.user.ILoginUserContext;
import kevin.framework.basic.common.user.IUserOperatorRecorder;
import kevin.framework.basic.common.user.LoginUser;
import kevin.framework.basic.common.user.UserFunc;

public class RequestInterceptor implements HandlerInterceptor {

    public final Logger logger = LoggerFactory.getLogger(RequestInterceptor.class);
    static Pattern pageUrlPattern = null;
    static String contextPath = null;

    private Map<String, LanguageMap> languageMap = LanguageStore.getLanguageStore();

    long maxSize;

    public long getMaxSize() {
        return maxSize;
    }

    public void setMaxSize(long maxSize) {
        this.maxSize = maxSize;
    }

    /**
     * 登陆用户的上下文
     ***/
    protected ILoginUserContext loginUserCtx;

    @Resource(name = "loginUserContext")
    public void setLoginUserCtx(ILoginUserContext loginUserCtx) {
        this.loginUserCtx = loginUserCtx;
    }

    /****
     * 用户操作日志记录器
     ******/
    protected IUserOperatorRecorder recorder;

    public void setRecorder(IUserOperatorRecorder recorder) {
        this.recorder = recorder;
    }

    public String getLang(String key) {
        LoginUser user;
        String lang = null;
        try {
            user = loginUserCtx.getCurrentUser();
            lang = user.getLang();
        } catch (Exception e) {
            // logger.error("",e);
        }
        if (StringUtils.isEmpty(lang)) {
            lang = SysConfigParams.lang;
        }
        LanguageMap map = languageMap.get(lang);
        if (map == null) {
            return "";
        }
        return map.getLangByKey(key);
    }

    private void putRecord(UrlInfo urlInfo, HttpServletRequest arg0, Exception arg3) throws Exception {
        if (recorder != null && loginUserCtx.getCurrentUser() != null) {
            LoginUser u = loginUserCtx.getCurrentUser();
            recorder.requestAspect(u, arg0);
            boolean success = arg3 == null;
            OperatorRecord record = recorder.createOperatorRecord(u, arg0);
            if (record == null) {
                record = new OperatorRecord();
                record.setUrl(arg0.getRequestURI());
                record.setUserId(u.getUserName() + "[" + u.getAccount() + "]");
                record.setSuccesful(success);
                record.setIp(loginUserCtx.getCurrentUser().getLoginIp());
                Object data = OperatorDataHolder.getData();
                record.setOpertorData(data);
                record.setException(arg3);
                record.setUrl(arg0.getRequestURI());
                record.setContextPath(arg0.getContextPath());
                record.setCmd(arg0.getParameter("cmd"));
                record.setRequestParamMap(arg0.getParameterMap());
            } else {
                Object data = OperatorDataHolder.getData();
                record.setOpertorData(data);
            }
            recorder.record(record, urlInfo);
            OperatorDataHolder.clear();
        }
    }

    /***
     * 在controller执行后执行
     **/
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
        throws Exception {

        boolean isDebug = SysConfigParams.isDevModel;
        arg0.setAttribute("isDebug", isDebug);

        UrlInfo urlInfo = AdminControllerHelper.getControllerAndCmd(arg0);
        String requestAction = urlInfo.getCmd();
        boolean isPageRequest = "page".equals(requestAction);

        boolean isGet = "GET".equals(arg0.getMethod());

        if (arg3 != null) {
            Map<String, String> langMap = (Map<String, String>)arg0.getAttribute("Lang");
            String errMsg = arg3.getMessage();
            if (errMsg == null) {
                Throwable throwable = arg3.getCause();
                if (throwable != null) {
                    errMsg = throwable.getMessage();
                }
                logger.error("HttpServletRequest afterCompletion {}", arg3);
            }

            if (isGet && isPageRequest) {
                //
                // String res = "<body>\r\n" +
                // " <h5>"+langMap.get("common_reqException")+"</h5>\r\n" +
                // " <div>\r\n" +
                // " "+arg3.getMessage()+"\r\n" +
                // " </div>\r\n" +
                // "</body>";
                // arg1.setCharacterEncoding("utf-8");
                // arg1.setContentType("text/html");
                // OutputStream out = arg1.getOutputStream();
                // out.write(res.getBytes("utf-8"));
                /*
                 * arg0.setAttribute("errorp", langMap.get("common_reqException"));//
                 * arg0.setAttribute("error", arg3);
                 * arg0.getRequestDispatcher("/WEB-INF/views/error.html").forward(arg0, arg1);
                 */
            } else {
                arg1.setCharacterEncoding("utf-8");
                arg1.setContentType("application/json");
                JSONObject j = new JSONObject();
                j.put("DEVMODEL", SysConfigParams.isDevModel);
                j.put("details", "<p>" + errMsg + "</p>");
                AjaxResult jresult = new AjaxResult(1, langMap.get("common_reqException"), j, false);
                try {
                    arg1.getWriter().write(JSONObject.toJSONString(jresult));
                } catch (IOException e) {
                    logger.error("{}", e);
                }
            }
        }
        try {
            putRecord(urlInfo, arg0, arg3);
        } catch (Exception e) {
            e.printStackTrace();
        }
        arg3 = null;
        ThreadHolderClearer.clear();
        /*
         * if(arg3!=null){ success=false; arg0.setAttribute("DEVMODEL",
         * SysConfigParams.isDevModel); String requestUrl = arg0.getRequestURI(); String
         * contextPath = arg0.getContextPath(); // ---- 路由规则
         * ==/应用名称/controller/action---// String regexExp = "^(" + contextPath +
         * ")(/\\S+)(/\\S+)$"; Pattern pattern = Pattern.compile(regexExp); Matcher
         * matcher = pattern.matcher(requestUrl); logger.error("{}",arg3); arg1.reset();
         * String errMsg=arg3.getMessage(); if(errMsg==null)
         * errMsg=arg3.getCause().getMessage(); if (matcher.matches()) { String
         * actionName = matcher.group(3); if(actionName.equals(Index)){
         * arg0.setAttribute("errorp", "请求发生异常，信息如下："); arg0.setAttribute("errormsg",
         * errMsg); arg0.getRequestDispatcher(SysConfigParams.errPage).forward(arg0,
         * arg1); }else{ arg1.setCharacterEncoding("utf-8");
         * arg1.setContentType("application/json"); JSONObject j=new JSONObject();
         * j.put("DEVMODEL", SysConfigParams.isDevModel);
         * j.put("details","<p>"+errMsg+"</p>"); AjaxResult jresult = new
         * AjaxResult(1,"<h2 class='alert_h2'>对不起，请求发生异常</h2>",j,false); try {
         * arg1.getWriter().write(JSONObject.toJSONString(jresult)); } catch
         * (IOException e) { logger.error("{}",e); } } } }
         */
    }

    /***
     * 在controller执行之后，在返回ModelAndView之前执行
     ****/
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
        throws Exception {
        // System.out.println("***************postHandle........");
    }

    /*****
     * 在controller执行前
     ******/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {

        ThreadHolderClearer.clear();
        ResponseThreadHolder.setResponse(response);
        RequestThreadHolder.setRequest(request);

        boolean isGet = "GET".equals(request.getMethod());
        if (isGet) {
            boolean isDebug = SysConfigParams.isDevModel;
            String jsVer = SysConfigParams.getConfig("jsversion");
            if (isDebug) {
                jsVer = DateUtils.formatCurrentDateTime("yyyyMMddhhmmss");
            }
            request.setAttribute("jsversion", jsVer);
            request.setAttribute("scruuid", SysConfigParams.getConfig("desKey"));
        }

        UrlInfo urlInfo = AdminControllerHelper.getControllerAndCmd(request);
        if (urlInfo.isRootRequest()) {
            response.sendRedirect(urlInfo.getCtx() + SysConfigParams.getConfig("loginController"));
            // request.getRequestDispatcher(SysConfigParams.getConfig("loginController")).forward(request,response);
            return false;
        }
        if ("logout".equals(urlInfo.getCmd())) {// 退出登录日志
            putRecord(urlInfo, request, null);
        }
        // 将语言文件的访问对象设置到setAttribute中
        String lang = SysConfigParams.getConfig("lang");
        LanguageMap languageMap = LanguageStore.getLanguageMap(lang);
        Map<String, String> langMap = languageMap.getLangMap();
        request.setAttribute("Lang", langMap);
        LangThreadHodler.setMap(langMap);
        // 将get请求的参数放入Attribute，方便在页面使用
        if ("GET".equals(request.getMethod())) {
            Map<String, String[]> paramsMap = request.getParameterMap();
            for (Entry<String, String[]> entry : paramsMap.entrySet()) {
                request.setAttribute(entry.getKey(), entry.getValue()[0]);
            }
        }
        if (SpringContextUtil.needToSetWebContext) {
            WebApplicationContext ac2 = RequestContextUtils.findWebApplicationContext(request);
            SpringContextUtil.setWebContext(ac2);
        }
        if (contextPath == null) {
            contextPath = request.getContextPath();
        }
        String authKey = urlInfo.getAuthController();
        String actionName = urlInfo.getCmd();

        // 判断是否不需要登录就可以直接访问
        if (SysConfigParams.canAccess(authKey, actionName)) {
            return true;
        }
        // //判断是否已经登录
        LoginUser user = loginUserCtx.getCurrentUser();
        boolean isLogin = user != null;
        /*
         * String method = request.getMethod(); String requestUrl =
         * request.getRequestURI();
         */

        if (isLogin) {
            String userId = user.getId();
            request.setAttribute("loginUserId", userId);
            if ("0".equals(userId)) {// 超级管理员
                return true;
            }
            boolean except = SysConfigParams.exceptValidation(authKey, actionName);
            if (except) {
                return true;
            }

            Map<String, List<UserFunc>> authMap = loginUserCtx.getLoginUserAuthMap(user);// 获取用户的权限集合
            List<UserFunc> funcList = authMap.get(authKey);
            boolean hasAuth = false;
            if ("page".equals(actionName)) {
                hasAuth = true;
            } else {
                if (funcList != null) {
                    for (UserFunc f : funcList) {
                        if (f.getFuncCode().equals(actionName)) {
                            hasAuth = true;
                            break;
                        }
                    }
                }
            }
            // 开发高权限的测试用户，但是过滤，新增，删除，编辑操作
            if ("981be07010f011e9b0c93c970e751c70".equals(userId)) {
                if (actionName.equals("update") || actionName.equals("delete") || actionName.equals("add")
                    || actionName.equals("funcMrg") || actionName.equals("roleUpdate") || actionName.equals("editor")) {
                    hasAuth = false;
                }
            }
            if (hasAuth) {
                return true;
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug(request.getRequestURI() + ";authKey=" + authKey + ",cmd=" + actionName
                        + getLang("common_noAuthor"));
                }
                if (actionName.equals("page")) {
                    request.getRequestDispatcher("/" + SysConfigParams.getConfig("on_author_action")).forward(request,
                        response);
                } else {
                    String isifr = request.getParameter("isifr");
                    if (StringUtils.isEmpty(isifr)) {
                        response.setContentType("apolication/json");
                    } else {
                        response.setContentType("text/html");
                    }
                    response.reset();
                    response.setCharacterEncoding("utf-8");
                    String json = "{\"strConvert\":false,\"code\":99999,\"message\":\"" + getLang("common_noAuthor")
                        + "\",\"data\":\"\"}";
                    response.getWriter().write(json);
                    response.flushBuffer();
                }
                return false;
            }
        } else {
            if (actionName.equals("page")) {
                request.getRequestDispatcher("/" + SysConfigParams.getConfig("loginController")).forward(request,
                    response);
            } else {
                String isifr = request.getParameter("isifr");
                if (StringUtils.isEmpty(isifr)) {
                    response.setContentType("apolication/json");
                } else {
                    response.setContentType("text/html");
                }
                response.reset();
                response.setCharacterEncoding("utf-8");
                String json = "{\"strConvert\":false,\"code\":99999,\"message\":\"" + getLang("common_notlogin")
                    + "\",\"data\":\"notlogin\"}";
                response.getWriter().write(json);
                response.flushBuffer();
            }
            return false;
        }
    }
}
